/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ui;

import java.awt.Component;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.JLabel;

/**
 *
 * @author Александр
 */
public class ActionScript {
    private JComponent mComponent;
    private Vector <Action> mMovements = new Vector<>();
    private Vector <Integer> mWaitSteps = new Vector<>();
    private Vector <Integer> mSyncMoments = new Vector<>();
            
    
    
    public ActionScript(JComponent component, Action movement, int waitSteps) {
        mMovements.add(movement);
        mWaitSteps.add(waitSteps);
        mComponent = component;
    }

    ActionScript(JComponent component) {
        mComponent = component;
    }
    
    
    public void addMovement(Action movement, int waitSteps) {
        mMovements.add(movement);
        mWaitSteps.add(waitSteps);
    }
    
    
    public void addRotate(Orientation orientation, int delaySteps) {
        
    }
    
    
    public void addSyncMoment() {
        if( !mMovements.isEmpty() ) {
            mSyncMoments.add(mMovements.size() - 1);
        }
    }
    
    public void execute() throws InterruptedException {
        
        if(mSyncMoments.isEmpty()) {
            execute(mMovements);
        } else {
            int iBegin = 0;
            int iEnd = 0;
            
            for(Integer iMovement: mSyncMoments) {
                iEnd = iMovement;
                execute( (List<Action>) mMovements.subList(iBegin, iEnd) );
                iBegin = iEnd;
            }
            execute( (List<Action>) mMovements.subList(iBegin, mMovements.size() ) );
            Thread.sleep(50);
        }
        
        clear();
    }
    

    private void execute(List<Action> movements) throws InterruptedException {
      
        if(movements.isEmpty()) {
            clear();
            return;
        }
        
        int amountOfMovements = movements.size();
        Vector <Integer> dx = new Vector();
        Vector <Integer> dy = new Vector();
        Vector <Integer> currDx = new Vector();
        Vector <Integer> currDy = new Vector();
        Vector <Float> buffDx = new Vector(); // "накопитель" смещения по x
        Vector <Float> buffDy = new Vector(); // .. больше нуля, чтобы скомпенсировать неточность float
        Vector <Float> dxStep = new Vector();
        Vector <Float> dyStep = new Vector();
        Vector <Point> destPoint = new Vector();
        Vector <Boolean> isMoveAlready = new Vector();
        Vector <Integer> stepsPerRepaint = new Vector();
        Vector <Integer> iStep = new Vector();    // Индекс шага
        Vector <Float> distance = new Vector();
        
        
        Vector <Boolean>isEndMove = new Vector();
        HashMap<JComponent, Integer> stepsBefore = new HashMap();
        
        int iMovement = 0;
        for(Action movement: movements) {
            
            currDx.add(0); // текущее смещение по x
            currDy.add(0); // текущее смещените по y
            buffDx.add((float) 0.05); // "накопитель" смещения по x
            buffDy.add((float) 0.05); // .. больше нуля, чтобы скомпенсировать неточность float
            
            dxStep.add((float)0);
            dyStep.add((float)0);
            distance.add((float)0);

            stepsPerRepaint.add(9);
            iStep.add(0);
            mWaitSteps.add(100);
            
            isMoveAlready.add(Boolean.FALSE);
            
            // Эти три значения определяются динамически в дальнейшем
            dx.add(0);
            dy.add(0);
            destPoint.add(new Point(0, 0));
            isEndMove.add(false);
            
            iMovement++;
        }
            
        Vector <Component>alreadyMoved = new Vector();
        Vector <Component>firstMovementAlreadyEnd = new Vector();
        
        boolean isEndScript = false;
        int currFirstMovement = 0;
        int delay = 0;
        float tmp;
        Action currAction;
        
        
        int deleteThis = 0;
        while(!isEndScript) {
            
            isEndScript = true;
            alreadyMoved.clear();
            boolean isFirst = true;
            for( iMovement = currFirstMovement; iMovement < amountOfMovements; iMovement++) {
                
                if( isEndMove.get(iMovement) ) {
                    if(isFirst) {
                        isFirst = false;
                        currFirstMovement = iMovement;
                    }
                    continue;
                }
                
                currAction = movements.get(iMovement);
                //if( currAction.mPreviousComponent != null ) {
                if( iMovement == 9 ) {
                        deleteThis++;
                        if( deleteThis > 62 ) {
                            int ghj = 1334;
                            ghj++;
                        }
                }
                
                if(alreadyMoved.contains(currAction.getComponent())) { //||
     //                   alreadyMoved.contains(currAction.mPreviousComponent)) {
                    isEndScript = false;
                    continue;
                }
                alreadyMoved.add(currAction.getComponent());
               

                
                if( iStep.get(iMovement) < 0 ) {
                    iStep.set(iMovement, iStep.get(iMovement) + stepsPerRepaint.get(iMovement));
                    isEndScript = false;
                    continue;
                } else if( ! isMoveAlready.get(iMovement) ) {
                    dx.set(iMovement, movements.get(iMovement).getDx());
                    dy.set(iMovement, movements.get(iMovement).getDy());
                    
                    // Если движение нулевое
                    if( dx.get(iMovement) == 0 && dy.get(iMovement) == 0 ) {
                        
                        if(!firstMovementAlreadyEnd.contains(currAction.getComponent())) {
                            
                            if( alreadyMoved.contains(currAction.mPreviousComponent) ) {
                                continue;
                            }
                            
                            if(firstMovementAlreadyEnd.contains(currAction.mPreviousComponent)) {
                                iStep.set(iMovement, 0);
                            } else {
                                delay -= currAction.getDelay();
                                iStep.set(iMovement, delay);
                            }
                            
                            firstMovementAlreadyEnd.add(currAction.getComponent());
                            
                            
                            
                            continue;
                            
                        }
                        
                        
                        alreadyMoved.remove(currAction.getComponent());
                        isEndMove.set(iMovement, true);
                        
                        
                        if( movements.get(iMovement).isRotate() ) {
                            rotate(currAction);
                        }
                        turnFace(currAction);
                        
                        updateLabelText(currAction);
                        updateZOrder(currAction);
                        
                        continue;
                    }

                    isMoveAlready.set(iMovement, true);
                    
                    destPoint.set( iMovement, currAction.getDestination());
                    
                    distance.set(iMovement, currAction.getDistance());
                    // приращение при каждом шаге (кадре) перемещения карты
                    dxStep.set(iMovement, dx.get(iMovement) / (float) distance.get(iMovement));
                    dyStep.set(iMovement, dy.get(iMovement) / (float) distance.get(iMovement));
                    
                    int tmpDelay = 0;
                    if( ! firstMovementAlreadyEnd.contains(currAction.getComponent()) ) {
                        delay -= currAction.getDelay();
                        tmpDelay = delay;
                    } else {
                        tmpDelay = 0;
                    }
                    iStep.set(iMovement, tmpDelay);
                    
                    if(stepsBefore.containsKey(currAction.getComponent())) {
                        stepsBefore.put(
                            movements.get(iMovement).getComponent(), 
                            Math.round(distance.get(iMovement)) + stepsBefore.get(movements.get(iMovement).getComponent()));
                    } else {
                        stepsBefore.put(
                            movements.get(iMovement).getComponent(), 
                            Math.round(distance.get(iMovement)));
                    }
                    
                    
                    iStep.set(iMovement, iStep.get(iMovement) + stepsPerRepaint.get(iMovement));
                    isEndScript = false;
                    
                    continue;
                }
                    
                if( iStep.get(iMovement) < distance.get(iMovement) - stepsPerRepaint.get(iMovement) ) {    
                    //for(iStep = 0; iStep < distance[iComponent] - stepsPerRepaint;
                    // iStep += stepsPerRepaint ) {
                    // находим смещение в шаге по горизонтали (currDx)
                    buffDx.set(iMovement, buffDx.get(iMovement) + dxStep.get(iMovement) * stepsPerRepaint.get(iMovement));
                    tmp = buffDx.get(iMovement);
                    currDx.set(iMovement, (int) tmp);
                    buffDx.set(iMovement, buffDx.get(iMovement) - (int)tmp);

                    // находим смещение в шаге по вертикали (currDy)
                    buffDy.set(iMovement, buffDy.get(iMovement) + dyStep.get(iMovement) * stepsPerRepaint.get(iMovement));
                    tmp = buffDy.get(iMovement);
                    currDy.set(iMovement, (int) tmp);
                    buffDy.set(iMovement, buffDy.get(iMovement) - (int)tmp);

                    isEndScript = false;
                        
                } else if( iStep.get(iMovement) < distance.get(iMovement) ) {     
                    

                    
                    
                 // последний кадр должен поставить карту в её точное конечное положение
                    currDx.set(iMovement, 
                            destPoint.get(iMovement).x - movements.get(iMovement).getComponent().getX());
                    currDy.set(iMovement, 
                            destPoint.get(iMovement).y - movements.get(iMovement).getComponent().getY());
                    alreadyMoved.remove(movements.get(iMovement).getComponent());
                    isEndMove.set(iMovement, true);
                    
                    firstMovementAlreadyEnd.add(movements.get(iMovement).getComponent());
                    
                    if( movements.get(iMovement).isRotate() ) {
                        rotate(movements.get(iMovement));
                    }
                    turnFace(movements.get(iMovement));
                    updateLabelText(currAction);
                    updateZOrder(currAction);
                    
                }
                
                if( iStep.get(iMovement) <= distance.get(iMovement) ) {
                    // смещаем карту на 1 кадр
                    moveComponentStep(movements.get(iMovement).getComponent(), 
                            currDx.get(iMovement), currDy.get(iMovement));
                    
                    iStep.set(iMovement, iStep.get(iMovement) + stepsPerRepaint.get(iMovement));
                }
                
            }
            Thread.sleep(10);
        }
    }
    
    
    
       /**
     * Передвинуть компонент, находящийся на панели (содержимое будет перерисовано)
     * @param component двигаемый компонент 
     * @param dx смещение по горизонтали
     * @param dy смещение по вертикали
     * @param sleepMs время сна в миллисекундах
     * @throws InterruptedException 
     */
    private void moveComponentStep(Component component, int dx, int dy) throws InterruptedException {
       int x = component.getX();
       int y = component.getY();
        
       component.setLocation(x + dx, y + dy);
       
       // перерисовываем прямоугольник, охватывающий и старую, 
       // и новую (после перемещения) область сдвинутого компонента 
       ((JComponent)mComponent.getParent()).paintImmediately(
            dx < 0 ? (x + dx) : x,
            dy < 0 ? (y + dy) : y,
            component.getWidth() + Math.abs(dx),
            component.getHeight() + Math.abs(dy)
            );
    }
    
    
    public void clear() {
        mMovements.clear();
        mWaitSteps.clear();
        mSyncMoments.clear();
    }
    
    
    public void rotate(Action m) {
        JLabel label = ((UICard)m.getRotatableComponent()).getLabel();
        m.getRotatableComponent().setOrientation(m.getOrientation());
        
        // перерисовываем прямоугольник, охватывающий и старую, 
        // и новую (после перемещения) область сдвинутого компонента 
        int x = label.getX();
        int y = label.getY();
        int length = Math.max(label.getWidth(), label.getHeight());
        ((JComponent)label.getParent()).paintImmediately(x, y, length, length);
    }
    
    public void turnFace(Action m) {
        boolean isNeedRepeint = false;
        if(m.isTurnFaceUp()) {
            isNeedRepeint = true;
            m.getUICard().turnFaceUp();
        } else if(m.isTurnFaceDown()) {
            isNeedRepeint = true;
            m.getUICard().turnFaceDown();
        }
        
        if(isNeedRepeint) {
            JLabel label = m.getUICard().getLabel();
            int x = label.getX();
            int y = label.getY();
            ((JComponent)label.getParent()).paintImmediately(x, y, label.getWidth(), label.getHeight());
        }
    }
    
    
    public void updateLabelText(Action action) {
        if(action.isLabelTextChange()) {
            JLabel label = action.getLabelForText();
            label.setText(action.getTexLabel());
    
            int x = label.getX();
            int y = label.getY();
            ((JComponent)label.getParent()).paintImmediately(x, y, label.getWidth(), label.getHeight());
        }
    }
    
    public void updateZOrder(Action action) {
        if(action.isZOrderChange()) {
            action.getUICardForZOrderChange().setZOrder(action.getZOrder());
        }
    }
}
